/*	____________________________________________________________________________

	           Semantics and Coding Component for the PhiMP Compiler
	____________________________________________________________________________  */

#ifndef CODEGEN
#define CODEGEN

#include <string>
#include <vector>
using namespace std;

#include "scan.h"


enum OpKind { PLUS, MINUS, MULT, DIV, INT_DIV, INT_MOD, POWER, LT, LE, EQ, NE, GE, GT };

struct OpRec // information about an operator
{
	OpKind op; // operator type
};

enum ExprKind { ID_EXPR, LITERAL_EXPR, TEMP_EXPR };
enum DataType { BOOL, INT, REAL, CHAR, STRING, ADDRESS };

struct ExprRec // information about a constant, variable, or
               // an intermediate (temporary) result
{
   ExprKind kind;   // operand type
   DataType dataType;
   string   name;   // used when kind is ID_EXPR or TEMP_EXPR
   float    val;    // used when kind is LITERAL_EXPR
   //char		ch;		// used when dataType is CHAR; ACTUALLY NOT USED ATM
};

class CodeGen
{
public:

	CodeGen();
	// Initializes the code generator;

/* _____________________________________________________________________________ */

	void Assign(ExprRec target, ExprRec source);
	// Produces the assembly code for an assignment from Source to Target.

	void Finish();
	// Generates code to finish the program.

	void GenInfix(ExprRec e1, OpRec op, ExprRec e2, ExprRec& e);
	// Produces the assembly code for an infix operation.

	void BoolGenInfix(ExprRec e1, OpRec op, ExprRec e2, ExprRec& e, bool isIf, ExprRec NextAddress);

	void Negate(ExprRec& e);
	// Produces FN or IN depending on datatype

	void NewLine();
	// Produces the assembly code for starting a new output line.

	void ProcessId(ExprRec& e);
	// Declares the identifier in the token buffer and builds a
	// corresponding semantic record e.

	void ProcessLiteral(ExprRec& e);
	// Converts the literal found in the token buffer into numeric form
	// and builds a corresponding semantic record e.

	void ProcessOp(OpRec& o);
	// Produces an operator descriptor O for the operator in the token
	// buffer.

	void ReadId(ExprRec InVar);
	// Produces the assembly code for reading a value for InVar.

	void Start();
	// Initializes the compiler.

	void WriteExpr(ExprRec OutExpr);
	// Produces the assembly code for writing the value of OutExpr.

	void CheckId(ExprRec& e);
	// Declares s as a new variable and enters it into the symbol table when s
	// is not already in the symbol table.

	void Enter(ExprRec& e);
	// Enters s unconditionally into the symbol table.


	void StartForLoop(ExprRec start, ExprRec end, ExprRec& startLoop, ExprRec& endLoop, int forCount);

	void EndForLoop(ExprRec start, ExprRec step, ExprRec startLoop, ExprRec endLoop, int forCount);

	void CreateFunction(string name, string& EndFuncAddress);

	void FunctionCall(string name, string EndFuncAddress);

	void EndFunctionCall(string EndFuncAddress);

	void StartIfStatement(ExprRec BoolExpression, ExprRec& NextElifOrElseAddress);

	void EndIfStatement(ExprRec NextElifOrElseAddress);

	void ElseStatement(ExprRec NextElifOrElseAddress, ExprRec EndElseAddr);

	void EndElseStatement(ExprRec EndElseAddress);

	void ElifStatement(ExprRec BoolExpression, ExprRec& NextElif);
		
/* _____________________________________________________________________________ */

private:
	vector<ExprRec> intTable;
	vector<ExprRec> stringTable; // Holds the actual strings for later writing to the data area of the .asm file
	vector<ExprRec> charTable;
	vector<ExprRec> realTable;
	vector<ExprRec> boolTable;
	vector<ExprRec> addressTable;

	int  maxTemp;     // max temporary allocated so far; initially 0
	int  stringAddress; // keeps the starting address of a string
	int  floatAddress; // keeps track of float LITERALS

	void CreateVar(ExprRec& e);

	void WriteString(ExprRec e); 
	// Prints out the string that is currently stored in the Token buffer.

	void ExtractExpr(ExprRec e, string& s, int offset = 0);
	// Returns an operand representation s for the expression e.

	string ExtractOp(OpRec o, ExprRec e1, ExprRec e2);
	// Returns a representation for the operator o.

	void Generate(string s1, string s2, string s3 = "");
	// Produces the SAM assembly code for one or two operand instructions. 
	// s1 is the opcode; s2 and s3 are operands.

	void GetTemp(ExprRec& result);
	// Creates a temporary variable and puts its name in result.name

	void IntToAlpha(int val, string& str);
	// Makes a string representation for a positive integer val.

	bool LookUp(ExprRec& e);
	// Returns true if s is in the symbol table; otherwise,
	// false is returned.

	/****************************************************	C level additions	*******************************************/

	void IntToReal(ExprRec& e);
	// Makes a real representation for a int val.

	void FloatToAlpha(float val, string& str);
	// Makes a string representation for a float val.

	void GenModCode(ExprRec opnd1, ExprRec opnd2);

	void GenPowCode(ExprRec opnd1, ExprRec opnd2);

	void GenOtherOps(OpRec o, ExprRec e1, ExprRec e2);

	void GenBoolOps(OpRec o, ExprRec e1, ExprRec e2, bool IsLoop, ExprRec NextAddress);

	void DisplayIdents();



};

#endif